/*
	this file is part of SplitBot
	SplitBot: an attempt to a better AI in 0ad - see http://code.google.com/p/split-bot/

	SplitBot is (c) 2011-2012 Alexandre Hoyau and is released under the GPL License:

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License (GPL)
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU General Public License for more details.
	
	To read the license please visit http://www.gnu.org/copyleft/gpl.html
*/
/**
 * @author lexa
 */

package org.zeroad.splitbot.agent;

import org.zeroad.common_api.BaseAI;
import org.zeroad.common_api.ResourceSupply;
import org.zeroad.splitbot.agent.Agent;
import org.zeroad.common_api.Entity;
import org.zeroad.common_api.EntityCollection;
import org.zeroad.common_api.EntityTypeValues;
import org.zeroad.common_api.Utils;
import org.zeroad.splitbot.core.Point;
import org.zeroad.splitbot.core.Sequencer;
import org.zeroad.splitbot.core.Statistic;
import org.zeroad.splitbot.helper.MapHelper;
import org.zeroad.splitbot.helper.Debug0AD;
import org.zeroad.splitbot.helper.EntityHelper;

class ChiefAgent extends Agent 
{
	private var builderAgent1:BuilderAgent;
	private var builderAgent2:BuilderAgent;
	private var machinaSexualAgent:MachinaSexualAgent;
	private var workerAgent:WorkerAgent;
	/**
	 * array of attacker agents
	 * attackers do not need to be called onUpdate, the handle it themselves
	 */
	private var attackerAgentsArray:Array<AttackerAgent>;
	/**
	 * name of this agent
	 */
	public var name:String;

	public function new(botAI:BotAI, parentAgentUID:AgentUID, agentName:String) 
	{
		super(botAI, parentAgentUID);
		
		attackerAgentsArray = new Array();
		_attackPending = 0;
		
		// used because seed of javascript random function depends on the time elapsed
		//var randomSeed:Int = Math.round((botAI.playerData.popLimit + botAI.playerData.popLimit + botAI.map.height + botAI.map.width)/100);
		var randomSeed:Int = Date.now().getMinutes();
		
		Sequencer.getInstance().addTimer(this, onUpdate, randomSeed, 10);
		Sequencer.getInstance().addTimer(this, saySomething, 150, 500);
		name = agentName;
		botAI.chat("ChiefAgent "+name+" CREATED ("+agentUID+")");
	}
	/**
	 * used for debug
	 */
	public function saySomething(botAI:BotAI):Void 
	{
		botAI.chat("Agent " + name + " speeking. I have " 
			+ Statistic.peopleNumber + " people, "
			+ Statistic.buildersNumber + " workers, "
			+ Statistic.buildingsNumber + " buildings, "
			+ "resources: [" + Statistic.foodCount +", "+ Statistic.woodCount +", "+ Statistic.stoneCount +", "+ Statistic.metalCount +"]"
			);
	}
	/**
	 * update method called by the parent of this agent
	 */
	override public function onUpdate(botAI:BotAI):Void 
	{
		super.onUpdate(botAI);
		var entities:EntityCollection = botAI.entities;
		
		if (machinaSexualAgent == null)
		{
			takeEntities(entities);
			// create agents
			builderAgent1 = new BuilderAgent(botAI, agentUID);
			builderAgent2 = new BuilderAgent(botAI, agentUID);
			machinaSexualAgent = new MachinaSexualAgent(botAI, agentUID);
			workerAgent = new WorkerAgent(botAI, agentUID);

			// assign units
			var workers:EntityCollection = workerAgent.takeEntities(getBuilders(entities), agentUID, null, 4);
			builderAgent1.takeEntities(getWorkers(), agentUID);

			// assign buildings
			machinaSexualAgent.takeEntities(getBuildings(), agentUID);
			// but keep the civic center
			setAsMyEntity(machinaSexualAgent.getCivicCenter());
			
			// at the begining, put everyone to work on food and wood, whatever the resources are
			//workerAgent.gatherIdle(entities, workers, ResourceSupplyTypeValue.WOOD);

			// callbacks
			builderAgent1.onNewBuilding = onNewBuilding;
			builderAgent2.onNewBuilding = onNewBuilding;
			machinaSexualAgent.onNewUnitStart = onNewUnitStart;
		}
		else
		{
			// take decisions according to the game state
			// attack
			if (botAI.playerData.popCount >= 170 && _attackPending-- <= 0)
			{
				_attackPending = 80;
				attack(botAI);
				//return;
			}

			// choose what to build
			builderAgent1.goodTemplateNames = BuilderAgent.GOOD_TEMPLATE_NAMES;
				
			var barracks:EntityCollection = machinaSexualAgent.getBuildings([EntityHelper.TEMPLATE_STRUCTURE_BARRACKS]);
			if (botAI.playerData.popCount > 50)
			{
				// build defenses
  				builderAgent1.goodTemplateNames.push(EntityHelper.TEMPLATE_STRUCTURE_SCOUT_TOWER);                    
				// we have medium-high pop count
				// build attack
				// one of each attack building
				var templateNameAttack:String;
				for (templateNameAttack in EntityHelper.TEMPLATE_STRUCTURE_ATTACK_ARRAY)
				{
					if (machinaSexualAgent.getBuildings([templateNameAttack]).length <= 0)
					{
						builderAgent1.goodTemplateNames.push(templateNameAttack);
					}
				}
			}
			if (botAI.playerData.popCount < botAI.playerData.popLimit * 0.90 || botAI.playerData.popLimit >= 200)
			{
				// we are way under max pop limit
				if (machinaSexualAgent.getBuildings().length > 5)
				{
					// we are NOT at the begining
				}
				builderAgent1.goodTemplateNames.push(EntityHelper.TEMPLATE_STRUCTURE_FIELD);
				if (barracks.length < 6)
				{
					// we have few barracks
					builderAgent1.goodTemplateNames = builderAgent1.goodTemplateNames.concat([EntityHelper.TEMPLATE_STRUCTURE_FIELD,EntityHelper.TEMPLATE_STRUCTURE_BARRACKS]);
				}
				else
				{
					// never executed ?!
				}
			}
			else
			{
				// we almost reached max pop limit
				builderAgent1.goodTemplateNames = builderAgent1.goodTemplateNames.concat([EntityHelper.TEMPLATE_STRUCTURE_HOUSE, EntityHelper.TEMPLATE_STRUCTURE_HOUSE, EntityHelper.TEMPLATE_STRUCTURE_HOUSE]);
				//Debug0AD.log("Reach pop limit (" + botAI.playerData.popCount +" / "+ botAI.playerData.popLimit+") - "+builderAgent.goodTemplateNames);
			}
			builderAgent2.goodTemplateNames = builderAgent1.goodTemplateNames;

			// max % of women
			machinaSexualAgent.badTemplateNames = MachinaSexualAgent.BAD_TEMPLATE_NAMES;
			var women:EntityCollection = workerAgent.getWorkers().filter(function (ent:Entity, str:String) {
				return ent.templateName() == EntityHelper.UNIT_SUPPORT_FEMALE_CITIZEN;
			});
			if (women.length > Statistic.peopleNumber / 10 && women.length > 50)
			{
				machinaSexualAgent.badTemplateNames.push(EntityHelper.UNIT_SUPPORT_FEMALE_CITIZEN);
			}

			// update my agents
			builderAgent1.onUpdate(botAI);
			builderAgent2.onUpdate(botAI);
			machinaSexualAgent.onUpdate(botAI);
			workerAgent.onUpdate(botAI);
			
		}
	}
	/**
	 * an attack has just been started if _attackPending > 0
	 */
	private var _attackPending:Int;
	/**
	 * attack the nearest oponent's building
	 */
	public function attack(botAI:BotAI):Void
	{
		// take the workers
		var attackerAgent:AttackerAgent = new AttackerAgent(botAI, this.agentUID);
		var people:EntityCollection = EntityHelper.myPeopleUnits;

		// take all unassigned entities
		attackerAgent.takeEntities(EntityHelper.myPeopleUnits, agentUID);

		// take 80% of the men and 100% of idle
		var maxAttackers:Int = 30; // workers.length * 0.8;
		//var numAttackers:Int = 0;
		var attackers:EntityCollection = people.filter(function (ent:Entity, str:String) {
			if(ent.templateName() != EntityHelper.UNIT_SUPPORT_FEMALE_CITIZEN 
				//&& Math.random() < 0.8
				//&& (ent.isIdle() || numAttackers++ < maxAttackers )
			)
			{
				// no, because it takes from other attackers: attackerAgent.setAsMyEntity(ent);
				return true;
			}
			return false;
		});
		// no, because the entities have an owner allready 
		attackerAgent.takeEntities(attackers, workerAgent.agentUID, null, maxAttackers);
		
		// for machines
		attackerAgent.takeEntities(EntityHelper.myEntities, null, null, maxAttackers);
		
		attackerAgentsArray.push(attackerAgent);
		Debug0AD.log("One more attacker agent, that makes " + attackerAgentsArray.length+" attacker agents");
	}
	/**
	 * callback called by the builderAgent when a new building is ready
	 */
	function onNewBuilding(building:Entity)
	{
		machinaSexualAgent.setAsMyEntity(building);
	}
	/**
	 * callback used to tell the machinaSexualAgent, to which agent it should give a unit which is about to be created
	 */
	function onNewUnitStart(entity:Entity):Agent
	{
		var choicesArray:Array<Agent> = [];
		choicesArray.push(workerAgent);
		
		// add a worker once in a while, while there is less than MAX_NUM_WORKERS
		if (builderAgent1.getWorkers().length < 5)
		{
			choicesArray.push(builderAgent1);
		}
		else if (builderAgent2.getWorkers().length < 5)
		{
			choicesArray.push(builderAgent2);
		}
		return Statistic.choose(choicesArray);
	}
}